/**
 * 基于 Axios 的 HTTP 请求装饰器
 * 
 * 该模块提供用于定义 API 端点和 HTTP 方法的装饰器，
 * 使用 Axios 作为底层 HTTP 客户端。
 */
import {AxiosDecorator} from "./types";
import {AxiosInstance, AxiosRequestConfig} from "axios";
import {cloneDeep} from "lodash-es";
import {httpRequest, AxiosDescriptorConfig} from "./request";

/**
 * 用于设置 API 基础路径和 Axios 实例的装饰器
 * 
 * @param path - 该类中所有请求的基础路径
 * @param axiosInstance - 要使用的自定义 Axios 实例或实例名称
 * @returns 在原型上设置路径和 axiosInstance 的类装饰器
 */
const Api: AxiosDecorator = (path?: string, axiosInstance?: string | AxiosInstance) => {
    return (constructor) => {
        constructor.prototype.path = path || ''
        axiosInstance && (constructor.prototype.axiosInstance = axiosInstance)
        return constructor
    }
}

/**
 * 基础 HTTP 请求装饰器
 * 
 * @param config - Axios 请求配置
 * @returns 创建 HTTP 请求处理器的方法装饰器
 */
const Http = (config: AxiosRequestConfig) => {
    return function (target: any, propertyKey: string): any {
        const isStatic = typeof target === 'function'

        if (isStatic) {
            target[propertyKey] = (data: any, _conf = {}) => {

                const httpConfig = cloneDeep({ ...config, ..._conf })
                const module = target.prototype.path
                const axiosInstance = target.prototype.axiosInstance
                httpConfig.url = module + httpConfig.url
                return httpRequest(data, httpConfig, axiosInstance)
            }
        } else {
            Object.defineProperty(target, propertyKey, {
                get() {
                    return (data: any, _conf = {}) => {
                        const httpConfig = cloneDeep({ ...config, ..._conf })
                        const module = target.constructor.prototype.path + (this.modelPath || '')
                        const axiosInstance = target.constructor.prototype.axiosInstance
                        httpConfig.url = module + httpConfig.url
                        return httpRequest(data, httpConfig, axiosInstance)
                    }
                },
                set(v: any) {
                    this[propertyKey] = v
                }
            })
        }
    }
}

/**
 * 创建 GET 请求的装饰器
 * 
 * @param url - 端点 URL（附加到基础路径）
 * @param config - 额外的 Axios 请求配置
 * @returns 创建 GET 请求处理器的方法装饰器
 */
const Get = (url = '', config: AxiosRequestConfig = {}) => {
    const httpConfig = Object.assign(config, {
        url,
        method: 'GET'
    } as AxiosRequestConfig)
    return Http(httpConfig)
}

/**
 * 创建 POST 请求的装饰器
 * 
 * @param url - 端点 URL（附加到基础路径）
 * @param config - 额外的 Axios 请求配置
 * @returns 创建 POST 请求处理器的方法装饰器
 */
const Post = (url = '', config: AxiosRequestConfig = {}) => {
    const httpConfig = Object.assign(config, {
        url,
        method: 'POST'
    } as AxiosRequestConfig)
    return Http(httpConfig)
}

/**
 * 创建 PUT 请求的装饰器
 * 
 * @param url - 端点 URL（附加到基础路径）
 * @param config - 额外的 Axios 请求配置
 * @returns 创建 PUT 请求处理器的方法装饰器
 */
const Put = (url = '', config: AxiosRequestConfig = {}) => {
    const httpConfig = Object.assign(config, {
        url,
        method: 'PUT'
    } as AxiosRequestConfig)
    return Http(httpConfig)
}

/**
 * 创建 DELETE 请求的装饰器
 * 
 * @param url - 端点 URL（附加到基础路径）
 * @param config - 额外的 Axios 请求配置
 * @returns 创建 DELETE 请求处理器的方法装饰器
 */
const Delete = (url = '', config: AxiosRequestConfig = {}) => {
    const httpConfig = Object.assign(config, {
        url,
        method: 'DELETE'
    } as AxiosRequestConfig)
    return Http(httpConfig)
}

export { Api, Http, Get, Post, Put, Delete, AxiosDescriptorConfig }
